10 #define forn(i, n) for (int i = 0; i < (n); i++)
19 Vector(long double xi
, long double yi
): x(xi
), y(yi
) {};
21 long double length() {
35 Column(long double x
, long double y
, long double r
) : position(x
,y
), radius(r
) {};
39 typedef pair
<long double, long double> Interval
;
40 typedef pair
<Vector
, Vector
> Segment
;
43 inline long double length(const Segment
& s
) {
44 return Vector(s
.second
.x
- s
.first
.x
, s
.second
.y
- s
.first
.y
).length();
47 inline long double length(const Interval
& i
) {
48 assert(i
.first
<= i
.second
);
49 return i
.second
- i
.first
;
53 pair
< long double, bool > intersect_segments(const Segment
& s1
, const Segment
& s2
) {
55 Vector p2
= s1
.second
;
57 Vector p4
= s2
.second
;
59 long double den
= (p4
.y
-p3
.y
)*(p2
.x
-p1
.x
) - (p4
.x
-p3
.x
)*(p2
.y
-p1
.y
);
61 long double ua_num
= (p4
.x
-p3
.x
)*(p1
.y
-p3
.y
) - (p4
.y
-p3
.y
)*(p1
.x
-p3
.x
);
62 long double ub_num
= (p2
.x
-p1
.x
)*(p1
.y
-p3
.y
) - (p2
.y
-p1
.y
)*(p1
.x
-p3
.x
);
64 if (fabs(den
) < EPS
) {
65 // Caso en que los Segments son paralelos
66 if (fabs(ua_num
- ub_num
) < EPS
&& fabs(ub_num
) < EPS
) {
67 // Las rectas son coincidentes, esto no deberia ocurrir
70 return make_pair(0, false);
73 if (ub_num
/den
>= 0) {
74 return make_pair(ua_num
/den
, true);
76 return make_pair(0, false);
80 Interval
intersect_intervals(const Interval
& i1
, const Interval
& i2
) {
82 long double d0
= max(i1
.first
, i2
.first
);
83 long double d1
= min(i1
.second
, i2
.second
);
86 return Interval(0, 0);
88 return Interval(d0
, d1
);
93 Interval
dark_range(const Segment
& wall
, const Lamp
& lamp
, const Column
& column
) {
94 Vector
bisectriz(column
.position
.x
- lamp
.x
, column
.position
.y
- lamp
.y
);
95 long double p
= asin(column
.radius
/bisectriz
.length());
96 long double alpha
= bisectriz
.angle();
98 Vector
d1(cos(alpha
+ p
), sin(alpha
+ p
));
99 Vector
d2(cos(alpha
- p
), sin(alpha
- p
));
101 pair
< long double, bool > p1
= intersect_segments(wall
, Segment(lamp
, Vector(lamp
.x
+ d1
.x
, lamp
.y
+ d1
.y
)));
102 pair
< long double, bool > p2
= intersect_segments(wall
, Segment(lamp
, Vector(lamp
.x
+ d2
.x
, lamp
.y
+ d2
.y
)));
104 long double wall_length
= length(wall
);
106 // Se sabe que los puntos de interseccion estan ordenados correctamente
107 // porque el angulo de diferencia entre las semirectas es menor a 180,
108 // entonces no es necesario chequearlo.
113 return Interval(0, 0);
115 res
= Interval(0, p2
.first
);
119 res
= Interval(p1
.first
, 1);
121 res
= Interval(p1
.first
, p2
.first
);
125 res
= intersect_intervals(res
, Interval(0,1));
126 return Interval(res
.first
* wall_length
, res
.second
* wall_length
);
129 void invert_range(const list
<Interval
>& ints
, long double fin
, list
<Interval
>& out
) {
132 out
.push_back(Interval(0,fin
));
137 list
<Interval
>::const_iterator it
= ints
.begin();
139 out
.push_back(Interval(0, it
->first
));
144 list
<Interval
>::const_iterator itprev
= ints
.begin();
145 while (it
!= ints
.end()) {
146 out
.push_back(Interval(itprev
->second
, it
->first
));
151 if (itprev
->second
< fin
) {
152 out
.push_back(Interval(itprev
->second
, fin
));
157 void reduce_union(list
<Interval
>& l_o
, list
<Interval
>& out
) {
158 // elimino repetidos para acelerar el sort
161 for (list
<Interval
>::const_iterator it
= l_o
.begin(); it
!= l_o
.end(); it
++) {
162 if (it
->first
< it
->second
) {
163 l
.push_back(Interval(it
->first
, it
->second
));
164 } else if (it
->first
> it
->second
) {
170 if (!l
.size()) return;
174 list
<Interval
>::const_iterator it
= l
.begin();
179 while (it
!= l
.end()) {
181 if (other
.first
< other
.second
) {
182 if (other
.first
> cand
.second
) {
186 if (other
.second
> cand
.second
) {
187 cand
= Interval(cand
.first
, other
.second
);
198 long double solve(const list
<Lamp
>& lamps
, const list
<Column
>& columns
, int max_x
, int max_y
) {
200 walls
.push_back(Segment(Vector(max_x
,0), Vector(0, 0)));
202 long double total
= 0;
204 for (list
<Segment
>::iterator p
= walls
.begin(); p
!= walls
.end(); p
++) {
205 list
<Interval
> lit_on_this_wall
;
206 for (list
<Lamp
>::const_iterator l
= lamps
.begin(); l
!= lamps
.end(); l
++) {
207 list
<Interval
> dark_zones
;
208 for (list
<Column
>::const_iterator c
= columns
.begin(); c
!= columns
.end(); c
++) {
209 dark_zones
.push_back(dark_range(*p
, *l
, *c
));
212 list
<Interval
> merged_dark_zones
;
213 list
<Interval
> lit_zone
;
215 reduce_union(dark_zones
, merged_dark_zones
);
216 invert_range(merged_dark_zones
, length(*p
), lit_zone
);
218 lit_on_this_wall
.splice(lit_on_this_wall
.end(), lit_zone
);
221 list
<Interval
> merged_lit_on_this_wall
;
222 reduce_union(lit_on_this_wall
, merged_lit_on_this_wall
);
224 for (list
<Interval
>::iterator it
= merged_lit_on_this_wall
.begin(); it
!= merged_lit_on_this_wall
.end(); it
++) {
225 total
+= length(*it
);
235 int nl
, nc
, max_x
, max_y
;
238 scanf("%d %d %d %d", &nl
, &nc
, &max_x
, &max_y
);
240 if (!(nl
|| nc
|| max_x
|| max_y
)) {
245 list
<Column
> columns
;
250 scanf("%d %d", &x
, &y
);
251 lamps
.push_back(Lamp(x
,y
));
255 scanf("%d %d %d", &x
, &y
, &r
);
256 columns
.push_back(Column(x
, y
, r
));
259 printf("%.4Lf\n", solve(lamps
, columns
, max_x
, max_y
));